package de.jmda.mproc.swingui;

import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;

import javax.annotation.processing.Processor;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.event.ListSelectionEvent;

import org.apache.log4j.Logger;

import de.jmda.gui.swing.mvc.AbstractController;
import de.jmda.gui.swing.mvc.ControllerContextProvider;
import de.jmda.mproc.LaunchConfiguration;
import de.jmda.mproc.LaunchConfigurationBuilder;
import de.jmda.mproc.LaunchConfigurationBuilderData;
import de.jmda.mproc.Launcher;

/**                                                                                    
 * This class was initially generated by {@link de.jmda.gui.swing.mvc.ControllerSupportEnabledGeneratorJV6}.    
 * <p>                                                                                 
 * <code>ControllerSupportEnabledGeneratorJV6</code> will not regenerate this class,
 * hence modifications will not get lost due to subsequent generation by <code>ControllerSupportEnabledGeneratorJV6</code>.                                         
 */
class JPanelVisualProcessorController
		extends AbstractController<JPanelVisualProcessorModel>
{
	private final static Logger LOGGER =
			Logger.getLogger(JPanelVisualProcessorController.class);
	
	private final static AnnotationProcessorDictionary
			ANNOTATION_PROCESSOR_DICTIONARY = new AnnotationProcessorDictionary();

	private JPanelVisualProcessorControllerContext context;

	private JPanelVisualProcessorModel model;

	/**                                                                                   
	 * Constructor                                                                        
	 */
	JPanelVisualProcessorController(
			ControllerContextProvider controllerContextProvider)
	{
		super(controllerContextProvider);
		context =
		    (JPanelVisualProcessorControllerContext)
		    		controllerContextProvider.getControllerContext();
	}

	@Override
	public void refreshControllerContext()
	{
		context =
		    (JPanelVisualProcessorControllerContext)
		    		controllerContextProvider.getControllerContext();
	}

	@Override
	public void setModel(JPanelVisualProcessorModel model)
	{
		this.model = model;

		updateFromModelJListAnnotationProcessors();
		updateFromModelJPanelFileSetJavaSourceFiles();
	}

	private void updateFromModelJListAnnotationProcessors()
	{
		JList jList = context.getJListAnnotationProcessors();

		if (jList == null)
		{
			// jList is not initialised yet, leave
			return;
		}

		List<String> annotationProcessorClassNames =
		    model.getAnnotationProcessorClassNames();

		DefaultListModel defaultListModel = new DefaultListModel();

		for (String annotationProcessorClassName : annotationProcessorClassNames)
		{
			defaultListModel.addElement(annotationProcessorClassName);
		}

		jList.setModel(defaultListModel);

		if (defaultListModel.getSize() == 0)
		{
			context.getJButtonLaunch().setEnabled(false);
			context.getJButtonRemove().setEnabled(false);
		}
		else
		{
			context.getJButtonLaunch().setEnabled(true);
		}
	}

	private void updateFromModelJPanelFileSetJavaSourceFiles()
	{
		JPanel jPanel = context.getJPanelFileSetJavaSourceFiles();

		if (jPanel == null)
		{
			// jPanel is not initialised yet, leave
			return;
		}

		GridBagConstraints gridBagConstraints = new GridBagConstraints();
		
		gridBagConstraints.gridx = 0;
		gridBagConstraints.gridy = 0;
		gridBagConstraints.weightx = 1.0;
		gridBagConstraints.weighty = 1.0;
		gridBagConstraints.fill = GridBagConstraints.BOTH;

		JPanelFileSetJavaSourceFiles jPanelFileSetJavaSourceFiles =
		    new JPanelFileSetJavaSourceFiles(
		    		model.getjPanelFileSetJavaSourceFilesModel());

		jPanel.removeAll();
		jPanel.add(jPanelFileSetJavaSourceFiles, gridBagConstraints);
	}

	public void addActionPerformed(ActionEvent evt)
	{
		List<String> annotationProcessorNames;

		// fetch all annotation processor names from dictionary
		try
		{
			annotationProcessorNames = ANNOTATION_PROCESSOR_DICTIONARY.get();
		}
		catch (InterruptedException e)
		{
			LOGGER.error(
					"failure getting annotation processor names from dictionary\n", e);
			return;
		}
		catch (ExecutionException e)
		{
			LOGGER.error(
					"failure getting annotation processor names from dictionary\n", e);
			return;
		}
		
		// remove all processor names from list that are already in the model
		for (String alreadyContainedName : model.getAnnotationProcessorClassNames())
		{
			annotationProcessorNames.remove(alreadyContainedName);
		}

		if (annotationProcessorNames.size() > 0)
		{
			String annotationProcessorName =
			    (String) JOptionPane.showInputDialog(
			    		new JFrame(),
			        "annotation processor class names",
			        "select annotation processor to add",
			        JOptionPane.PLAIN_MESSAGE,
			        null,
			        annotationProcessorNames.toArray(new String[0]),
			        "ham");
	
			//If a string was returned, say so.
			if ((annotationProcessorName != null) &&
			    (annotationProcessorName.length() > 0))
			{
				model.getAnnotationProcessorClassNames().add(annotationProcessorName);
				updateFromModelJListAnnotationProcessors();
			}
		}
		else
		{
			JOptionPane.showMessageDialog(
					new JFrame(),
					"no (more) annotation processor classes available in classpath");
		}
	}

	public void removeActionPerformed(ActionEvent evt)
	{
		int selectedIndex = context.getJListAnnotationProcessors().getSelectedIndex();
		
		if (selectedIndex > -1)
		{
			model.getAnnotationProcessorClassNames().remove(selectedIndex);
			updateFromModelJListAnnotationProcessors();
		}
	}

	public void launchActionPerformed(ActionEvent evt)
	{
		List<String> processorClassNames = model.getAnnotationProcessorClassNames();
		
		if (processorClassNames.size() == 0)
		{
			LOGGER.debug("no annotation processor class names available");
			return;
		}
		
		List<Class<? extends Processor>> processorClasses =
				new LinkedList<Class<? extends Processor>>();
		
		for (String processorClassName : processorClassNames)
		{
			try
      {
	      processorClasses.add(
	      		(Class<? extends Processor>) Class.forName(processorClassName));
      }
      catch (ClassNotFoundException e)
      {
  			JOptionPane.showMessageDialog(
  					new JFrame(),
  					"failure finding class for [" + processorClassName + "]",
  					"can not launch annotation processing",
  					JOptionPane.ERROR_MESSAGE);
  			return;
      }
		}
		
		LaunchConfigurationBuilderData launchConfigurationBuilderData =
				new LaunchConfigurationBuilderData();

		launchConfigurationBuilderData.fileSetJavaSources =
				model.getjPanelFileSetJavaSourceFilesModel().getFileSetJavaFilesOnly();
		launchConfigurationBuilderData.processorClasses.addAll(processorClasses);
		
    LaunchConfiguration launchConfiguration = null;
    
    String errMsg = null;

    try
    {
	    launchConfiguration =
	    		LaunchConfigurationBuilder.build(launchConfigurationBuilderData);
    }
    catch (InstantiationException e)
    {
    	errMsg = "failure instantiating processor\n" + e;
    }
    catch (IllegalAccessException e)
    {
    	errMsg = "failure accessing processor\n" + e;
    }
    
    if (errMsg != null)
    {
			JOptionPane.showMessageDialog(
					new JFrame(),
					errMsg,
					"can not launch annotation processing",
					JOptionPane.ERROR_MESSAGE);
			return;
    }

    try
    {
	    Launcher.launch(launchConfiguration);
    }
    catch (IOException e)
    {
			JOptionPane.showMessageDialog(
					new JFrame(),
					e.toString(),
					"failure launching configuration",
					JOptionPane.ERROR_MESSAGE);
			return;
    }
	}

	public void annotationProcessorsValueChanged(ListSelectionEvent evt)
  {
		int selectedIndex = context.getJListAnnotationProcessors().getSelectedIndex();
		
		if (selectedIndex < 0)
		{
			context.getJButtonRemove().setEnabled(false);
		}
		else
		{
			context.getJButtonRemove().setEnabled(true);
		}
  }
}